/** @file
*
*  Copyright (c) 2011, ARM Limited. All rights reserved.
*  Copyright (C) 2022 - 2023, Phytium Technology Co., Ltd. All rights reserved.<BR>
*
*  SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/

#include <PiPei.h>

//
// The protocols, PPI and GUID definitions for this module
//
#include <Ppi/MasterBootMode.h>
#include <Ppi/BootInRecoveryMode.h>
#include <Ppi/GuidedSectionExtraction.h>
#include <Ppi/X100Info.h>
//
// The Library classes this module consumes
//
#include <Library/ArmPlatformLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
#include <Library/PeimEntryPoint.h>
#include <Library/PeiServicesLib.h>
#include <Library/PcdLib.h>
#include <Library/ArmSmcLib.h>
#include <Ppi/ReadOnlyVariable2.h>
#include <OemConfigData.h>
#include "PlatformPeim.h"
#include <Library/ParameterTable.h>
#include "mcu_info.h"
#include <Library/PhytiumPowerControlLib.h>
//#include <PcieConfigData.h>
#include "GpioInit.h"
//[gliu-0009]add-start
#include <Library/I2CLib.h>
#include <Library/SeLib.h>
//[gliu-0009]add-end
#include <Library/PeiKlSetupVarRWLib.h>
//[gliu-0004]
#include <Library/GenericWatchdogLib.h>
//[gliu-0004]
//[jckuang-0020]
//#include <Library/PeiSerialPortLib.h>
#include <Library/PostCodeLib.h>
#include "PostCode.h"
//[jckuang-0020]
#include "DebugCommon.h"

#define CPU_GET_PARAMETER_VERSION     0xC2000F00
#define CPU_GET_RST_SOURCE            0xC2000F01
#define CPU_INIT_PLL                  0xC2000F02
#define CPU_INIT_PCIE                 0xC2000F03
#define CPU_INIT_DDR                  0xC2000F04
#define CPU_RELOCATE                  0xC2000F05
#define CPU_SECURITY_CFG              0xC2000F07
#define CPU_GET_MEM_INFO              0xC2000F14

#define DDR_INIT                      0x0
#define DDR_SUSPEND_ENTRY             0x1
#define DDR_SUSPEND_LOCK              0x2
#define DDR_SUSPEND_UNLOCK            0x3
#define TAZ_AES_INIT                  0x6
#define DDR_FAST_TRAINNING            0xA
#define DDR_BIST                      0xB

#define POWER_ON_RESET   0x1
#define SOFT_WARM_RESET  0x2

#define PEU0_PHY_BASE 0x29200000
#define PEU1_PHY_BASE 0x29300000

#define TX_A0_LANX_BASE  0x10400
#define TX_A0_LANY_BASE  0x10C00
#define TX_A1_LANX_BASE  0x10404
#define TX_A1_LANY_BASE  0x10C04
#define TX_A2_LANX_BASE  0x10408
#define TX_A2_LANY_BASE  0x10C08
#define TX_A3_LANX_BASE  0x1040C
#define TX_A3_LANY_BASE  0x10C0C
#define TX_A4_LANX_BASE  0x10410
#define TX_A4_LANY_BASE  0x10C10
#define TX_A5_LANX_BASE  0x10414
#define TX_A5_LANY_BASE  0x10C14
#define RX_A0_LANX_BASE  0x20000
#define RX_A0_LANY_BASE  0x20800
#define RX_A1_LANX_BASE  0x20004
#define RX_A1_LANY_BASE  0x20804
#define RX_A2_LANX_BASE  0x20008
#define RX_A2_LANY_BASE  0x20808
#define RX_A3_LANX_BASE  0x2000C
#define RX_A3_LANY_BASE  0x2080C
#define RX_A4_LANX_BASE  0x20010
#define RX_A4_LANY_BASE  0x20810
#define RX_A5_LANX_BASE  0x20014
#define RX_A5_LANY_BASE  0x20814

#define LAN_STEP      0x1000

BOOLEAN mOemConfigSueupExist = FALSE;
OEM_CONFIG_DATA  mOemConfigData;
VOID Pulldown(VOID);
VOID Alarm(UINTN   ErrorType);
VOID Alarm(UINTN   ErrorType);

EFI_STATUS
EFIAPI
InitializePlatformPeim (
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
  IN CONST EFI_PEI_SERVICES     **PeiServices
  );

EFI_STATUS
EFIAPI
PlatformPeim (
  VOID
  );

typedef struct {
  SYSTEM_SETUP_CONFIGURATION *Config;
  UINT8                      IsVariableValid;
} LocalPeiData;

VOID
ShowConfig(
  SYSTEM_SETUP_CONFIGURATION *SetupConfig
  )
{
  DEBUG ((EFI_D_INFO, "[%a:%d] SystemSetupConfig->CoreSpeed        : 0x%08lx\n", __FUNCTION__, __LINE__, SetupConfig->CoreSpeed));
  DEBUG ((EFI_D_INFO, "[%a:%d] SystemSetupConfig->LmuSpeed         : 0x%08lx\n", __FUNCTION__, __LINE__, SetupConfig->LmuSpeed));
  DEBUG ((EFI_D_INFO, "[%a:%d] SystemSetupConfig->FastTrainEnable  : 0x%08lx\n", __FUNCTION__, __LINE__, SetupConfig->FastTrainEnable));
  DEBUG ((EFI_D_INFO, "[%a:%d] SystemSetupConfig->AutoWakeUpConfig : 0x%08lx\n", __FUNCTION__, __LINE__, SetupConfig->AutoWakeUpConfig));

  ShowHexString("SystemSetupConfig->CoreSettingEnable", SetupConfig->CoreSettingEnable, sizeof(SetupConfig->CoreSettingEnable));
  ShowHexString("SystemSetupConfig->PcieSettingSplitMode", SetupConfig->PcieSettingSplitMode, sizeof(SetupConfig->PcieSettingSplitMode));
  ShowHexString("SystemSetupConfig->PcieSettingPeu0Enable", SetupConfig->PcieSettingPeu0Enable, sizeof(SetupConfig->PcieSettingPeu0Enable));
  ShowHexString("SystemSetupConfig->PcieSettingPeu1Enable", SetupConfig->PcieSettingPeu1Enable, sizeof(SetupConfig->PcieSettingPeu1Enable));
  ShowHexString("SystemSetupConfig->PcieSettingPeu0Speed", SetupConfig->PcieSettingPeu0Speed, sizeof(SetupConfig->PcieSettingPeu0Speed));
  ShowHexString("SystemSetupConfig->PcieSettingPeu1Speed", SetupConfig->PcieSettingPeu1Speed, sizeof(SetupConfig->PcieSettingPeu1Speed));
  ShowHexString("SystemSetupConfig->PcieSettingPeu0Eq", SetupConfig->PcieSettingPeu0Eq, sizeof(SetupConfig->PcieSettingPeu0Eq));
  ShowHexString("SystemSetupConfig->PcieSettingPeu1Eq", SetupConfig->PcieSettingPeu1Eq, sizeof(SetupConfig->PcieSettingPeu1Eq));
}
EFI_STATUS
EFIAPI
GetX100SataInfo (
  IN EFI_PEI_X100_INFO_PPI   *This,
  IN UINT8                   SataInfo,
  OUT UINT32                 *SataPi
);

//
// Module globals
//
CONST EFI_PEI_PPI_DESCRIPTOR  mPpiListBootMode = {
  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
  &gEfiPeiMasterBootModePpiGuid,
  NULL
};

CONST EFI_PEI_PPI_DESCRIPTOR  mPpiListRecoveryBootMode = {
  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
  &gEfiPeiBootInRecoveryModePpiGuid,
  NULL
};

STATIC EFI_PEI_X100_INFO_PPI     mX100InfoPpi = {
  GetX100SataInfo
  };

CONST EFI_PEI_PPI_DESCRIPTOR  mPpiListX100Info = {
  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
  &gEfiPeiX100InfoPpiGuid,
  &mX100InfoPpi
};

EFI_STATUS
VariableGet(
  LocalPeiData *PeiDataPtr
  )
{
  EFI_STATUS Status;
  SYSTEM_SETUP_CONFIGURATION *SetupVar;

    Status = PeiKlSetupVarRead(&SetupVar);
    if (!EFI_ERROR (Status)) {
      PeiDataPtr->IsVariableValid = TRUE;
    
      PeiDataPtr->Config = AllocateZeroPool(sizeof(SYSTEM_SETUP_CONFIGURATION));
      if (!PeiDataPtr->Config) {
        DEBUG ((DEBUG_ERROR, "[+][%a:%d] allocate pool failed.\n", __FUNCTION__, __LINE__));
        return EFI_OUT_OF_RESOURCES;
      } else {
        CopyMem(PeiDataPtr->Config, SetupVar, sizeof(SYSTEM_SETUP_CONFIGURATION));
      }
      ShowConfig(PeiDataPtr->Config);

      FreePool(SetupVar);
    }

  return Status;
}

//#define  DDR_TRAIN_INFO_CHECK  0x524444

EFI_STATUS
CreatDdrTrainInfoHob (
  VOID
  )
{
  ARM_SMC_ARGS  ArmSmcArgs;
  UINT64        DdrInfoSrc;
  UINT64        DdrInfoSize;

  //
  //Get Ddr Training Info from pbf
  //
  ZeroMem (&ArmSmcArgs, sizeof(ARM_SMC_ARGS));
  ArmSmcArgs.Arg0 = CPU_GET_MEM_INFO;
  ArmCallSmc (&ArmSmcArgs);
  DEBUG ((EFI_D_INFO, "ArmSmcArgs.Arg0 : %d, %llx\n",ArmSmcArgs.Arg0,  ArmSmcArgs.Arg0));
  if ((0 == ArmSmcArgs.Arg0) || (-1 == (INT64) ArmSmcArgs.Arg0)) {
    DEBUG ((EFI_D_INFO, "Get ddr training info from pbf failed!\n"));
    return EFI_NOT_FOUND;
  }
  else {
    DdrInfoSrc = ArmSmcArgs.Arg0;
    DdrInfoSize = MmioRead64 (ArmSmcArgs.Arg0);
    DEBUG ((EFI_D_INFO, "Ddr Info Size : %d, Addr : %x\n", DdrInfoSize, DdrInfoSrc));
    BuildGuidDataHob (&gDdrTrainInfoAddrHobGuid, &DdrInfoSrc, sizeof (UINT64));
    return EFI_SUCCESS;
  }
  return EFI_SUCCESS;
}

BOOLEAN
CheckTrainInfo (
  UINT64  Addr
  )
{
  UINT64  Temp;
  Temp = MmioRead32 (Addr);
  DEBUG ((EFI_D_INFO, "Ddr Info check : %x\n", Temp));
  if (Temp == DDR_TRAIN_INFO_CHECK) {
    return TRUE;
  }
  else {
    return FALSE;
  }
}


/*
GetVariable (
  IN CONST CHAR16    *Name,
  IN CONST EFI_GUID  *Guid
  )

*/
EFI_STATUS
EFIAPI
SearchAnyVariable(
  IN CONST CHAR16 *Name,
  IN CONST EFI_GUID *Guid,
  IN OUT VOID *Variable,
  IN UINTN *VariableSize)
{
  EFI_STATUS Status;
  EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi;
  /*UINTN VariableSize = sizeof(OEM_CONFIG_DATA);*/

  Status = PeiServicesLocatePpi (
             &gEfiPeiReadOnlyVariable2PpiGuid,
             0,
             NULL,
             (VOID **)&VariablePpi
             );
  ASSERT_EFI_ERROR (Status);

  Status = VariablePpi->GetVariable(
             VariablePpi,
             Name,
             Guid,
             NULL,
             VariableSize,
             Variable
          );

  /*if(EFI_ERROR(Status)) {*/
      /*if(EFI_NOT_FOUND == Status) {*/
          /*return Status;*/
      /*} else {*/
        /*ASSERT_EFI_ERROR(Status);*/
      /*}*/
  /*}*/

  return Status;
}

UINT32 ReadDeviceId()
{
  UINT32 Reg = 0;

  MmioWrite32(0x28014010, 0x9F002040);
  Reg = MmioRead32(0x2801401C);
  return Reg;
}

VOID QspiSet(void)
{
  UINT32 DeviceId = 0;

  DeviceId = ReadDeviceId();
  DEBUG((EFI_D_INFO, "JEDEC Device ID:%x\n", DeviceId));

  //WriteEnable
  MmioWrite32(0x28014010, 0x06000000);
  MmioRead32(0x2801401C);
  //Set CR1V[1] to 1, CR1V Adress is 00800002
  MmioWrite32(0x28014010, 0x7100A000);
  MmioWrite32(0x28014014, 0x800002);
  MmioWrite32(0x2801401C, 0x2);
  //Set Flash Mode
  MmioWrite32(0x2801402C, 0xF0A0);
  //
  MmioWrite32(0x28014004, 0xEC4F407E);

  DEBUG((EFI_D_INFO, "%a() Line=%d, Reg=%x\n", __FUNCTION__, __LINE__, MmioRead32(0x28014004)));
}

VOID
ClearRTCInterrupt (
  VOID
  )
{
  UINT8         Temp;
  UINT64        I2CBaseAddress;
  UINT32        I2CSpeed;
  UINT32        RtcSlaveAddress;
  UINT8         Buffer1;
  UINT8         Buffer11;
  UINTN         Reg;
  I2CBaseAddress  = PcdGet64 (PcdRtcI2cControllerBaseAddress);
  I2CSpeed        = PcdGet32 (PcdRtcI2cControllerSpeed);
  RtcSlaveAddress = PcdGet32 (PcdRtcI2cControllerSlaveAddress);

  Reg = MmioRead32(0x28180200);
  MmioWrite32(0x28180200, (Reg & (~(0xff << 24))) | (0x22 << 24));
  Reg = MmioRead32(0x28180204);
  MmioWrite32(0x28180204, (Reg & (~(0xf << 28))) | (0x1 << 28));

  i2c_init(I2CBaseAddress, I2CSpeed, RtcSlaveAddress);
//[gliu-0043]add-start
#if HWQS
    (VOID)Temp;
    (VOID)Buffer11;
    Buffer1 = 0x0;
    i2c_write(I2CBaseAddress, RtcSlaveAddress, 0x0e, 1, &Buffer1, 1);
    Buffer1 = 0x0;
    i2c_write(I2CBaseAddress, RtcSlaveAddress, 0x0f, 1, &Buffer1, 1);
#else
//[gliu-0043]add-end
  if (RtcSlaveAddress == 0x32){

    //enable write
    i2c_read(I2CBaseAddress, RtcSlaveAddress, 0x10, 1, &Temp, 1);
    Temp |= (1 << 7);
    i2c_write(I2CBaseAddress, RtcSlaveAddress, 0x10, 1, &Temp, 1);

    i2c_read(I2CBaseAddress, RtcSlaveAddress, 0x0f, 1, &Temp, 1);
    Temp |= (1 << 2);
    Temp |= (1 << 7);
    i2c_write(I2CBaseAddress, RtcSlaveAddress, 0x0f, 1, &Temp, 1);

    //enable ARST
    Buffer1 = 0x80;
    i2c_write(I2CBaseAddress, RtcSlaveAddress, 0x11, 1, &Buffer1, 1);

    // clear interrupt
    i2c_read(I2CBaseAddress, RtcSlaveAddress, 0x0f, 1, &Buffer11, 1);
    DEBUG((EFI_D_INFO, "%a() Line=%d,0x0fh is %x\n", __FUNCTION__, __LINE__,Buffer11));
    i2c_read(I2CBaseAddress, RtcSlaveAddress, 0x10, 1, &Buffer11, 1);
    DEBUG((EFI_D_INFO, "%a() Line=%d,0x10h is %x\n", __FUNCTION__, __LINE__,Buffer11));
  } else if (RtcSlaveAddress == 0x68){
    Buffer1 = 0x5;
    i2c_write(I2CBaseAddress, RtcSlaveAddress, 0x0e, 1, &Buffer1, 1);
    Buffer1 = 0x0;
    i2c_write(I2CBaseAddress, RtcSlaveAddress, 0x0f, 1, &Buffer1, 1);
  }
#endif
}

UINT16
GetMaxFreq (
  VOID
  )
{
  UINT64              I2CBaseAddress;
  UINT32              I2CSpeed;
  UINT8               Buffer[SPD_NUM] = {0};
  UINT16              Temp;
  UINT32              SlaveAddress[2]= {0x50, 0x51};
  UINT8               i;
  UINT16              Temp2;

  Temp2 = 0xffff;
  I2CBaseAddress = PcdGet64 (PcdSpdI2cControllerBaseAddress);
  I2CSpeed = PcdGet32 (PcdSpdI2cControllerSpeed);
  //
  // Initialize I2C Bus which contain SPD
  //
  for (i = 0; i < 2; i++){
    i2c_init(I2CBaseAddress, I2CSpeed, SlaveAddress[i]);
    Temp = i2c_read(I2CBaseAddress, SlaveAddress[i], 0, 1, Buffer, 256);
    if (Temp == 0) {
      //Temp = (Buffer[18] *125 +Buffer[125] *1);
      //DEBUG((EFI_D_INFO,"(Buffer[18] *125 +Buffer[125] *1) is %d.\n",Temp));
      Temp = (1000000/(Buffer[18] *125 +(INT8)Buffer[125] *1))/2;
      DEBUG((EFI_D_INFO,"Temp is %d.\n",Temp));
      if (Temp == 666){
           Temp = 667;
      }else if(Temp == 466){
         Temp = 467;
      }

      DEBUG((EFI_D_INFO,"Temp is %d----.\n",Temp));
      if (Temp < Temp2){
        Temp2 = Temp;
      }
    }else{
       DEBUG((EFI_D_ERROR,"Get the DDR Max Freq fail.\n"));
    }
  }
  //DEBUG((EFI_D_INFO,"MaxDdrFrequency is %d.\n",MaxDdrFrequency));
  return Temp2;
}


UINT32
GetResetSource(
  VOID
  )
{
  ARM_SMC_ARGS                  ArmSmcArgs;

  SetMem((VOID*)&ArmSmcArgs, sizeof(ARM_SMC_ARGS), 0);
  ArmSmcArgs.Arg0 = CPU_GET_RST_SOURCE;
  ArmCallSmc (&ArmSmcArgs);

  return (UINT32)(ArmSmcArgs.Arg0);
}

  
/**
  Get X100  Sata Pi.

  @param[in]  SataInfo     The input Sata information of x100 chipset
  @param[out]  SataInfo	   The pointer of sata pi

  @retval UINT32         The X100 Sata pi value.

**/
EFI_STATUS
EFIAPI
GetX100SataInfo (
  IN EFI_PEI_X100_INFO_PPI   *This,
  IN UINT8                   SataInfo,
  OUT UINT32                 *SataPi
)
{
  UINT16                       SumNum;
  UINT16                       Num;
  SYSTEM_SETUP_CONFIGURATION   *SetupVar;
  X100_CONFIG *                X100ConfigVar;
  EFI_STATUS                   Status;

  if(SataPi == NULL) {
    DEBUG((EFI_D_ERROR, "GetX100SataInfo error: the satapi is NULL.\n"));
    return EFI_INVALID_PARAMETER;
  }
  Status = PeiKlSetupVarRead(&SetupVar);
  if(EFI_ERROR(Status)){
    DEBUG((EFI_D_ERROR, "GetX100SataAvailable:Get Setup Varible Failed.\n"));
    return Status;
  }
  if (SetupVar->X100Config.X100IsExisted == 0) {
    DEBUG((EFI_D_INFO, "x100 board is not insert!\n"));
    *SataPi = 0;
    return EFI_SUCCESS;
  }
  X100ConfigVar = &SetupVar->X100Config;
  SumNum = sizeof(X100ConfigVar->SataPort) / sizeof(X100ConfigVar->SataPort[0]);
  DEBUG((EFI_D_INFO, "X100 Sata used : %x\n", SataInfo));
  if (0) {
      //SATA master control is off
      *SataPi = 0;
  } else {
      if (0) {
        //  SATA master control is off
      } else {
        // SATA general control is enabled
        *SataPi = 0;
        for (Num = 0; Num < SumNum; Num++) {
            X100ConfigVar->SataPort[Num].IsUsed = (SataInfo >> Num) & 0x1;
            if (X100ConfigVar->SataPort[Num].IsUsed == 0) {
              X100ConfigVar->SataPort[Num].Enable = 0;
            }
            DEBUG((EFI_D_INFO, "X100 Sata Port[%d] Used : %d, Enable : %d\n",
                  Num,
                  X100ConfigVar->SataPort[Num].IsUsed,
                  X100ConfigVar->SataPort[Num].Enable));
                  *SataPi |= ((X100ConfigVar->SataPort[Num].Enable & 0x1) << Num);
           }
     }
  }

  DEBUG((EFI_D_INFO, "X100 Sata Pi : %0x\n", *SataPi));
  return EFI_SUCCESS;
}
  
STATIC
UINT32
GetCoreSpeed(
  IN LocalPeiData *PeiData
  )
{
  SYSTEM_SETUP_CONFIGURATION *SetupVar;
  UINT32                     CoreSpeed;

  CoreSpeed = 0;
  SetupVar = PeiData->Config;
  DEBUG ((EFI_D_INFO, "CoreSpeed: 0x%lx\n", &SetupVar->CoreSpeed));

  if (PeiData->IsVariableValid) {
    CoreSpeed = SetupVar->CoreSpeed;
  } else {
    DEBUG ((EFI_D_INFO, "Get Core Speed failed! Using Default.\n"));
    CoreSpeed  = 0;
  }

  return CoreSpeed;
}

STATIC
UINT32
GetLmuSpeed(
  IN LocalPeiData *PeiData
  )
{
  SYSTEM_SETUP_CONFIGURATION *SetupVar;
  UINT32                     LmuSpeed;

  LmuSpeed = 0;
  SetupVar = PeiData->Config;
  DEBUG ((EFI_D_INFO, "LmuSpeed: 0x%lx\n", &SetupVar->LmuSpeed));

  if (PeiData->IsVariableValid) {
    LmuSpeed = SetupVar->LmuSpeed;
  } else {
    DEBUG ((EFI_D_INFO, "Get LMU Speed failed! Using Default.\n"));
    LmuSpeed  = 0;
  }

  return LmuSpeed;
}


VOID
PllInit(
  IN UINT16 MaxDdrFrequency,
  IN LocalPeiData *PeiData
  )
{
  ARM_SMC_ARGS  ArmSmcArgs;
  EFI_STATUS    Status;
  UINT8 Buffer[0x100];
  PLL_CONFIG    *PllConfigData;
  UINT32         CoreSpeed = 0;
  UINT32         LmuSpeed = 0;

  UINT8         Buffer1[0x100];
  DDR_CONFIG    *DdrConfigData;

  POST_CODE_EX(EFI_PROGRESS_CODE, PEI_CPU_INIT);//[gliu-0062]
  GetParameterInfo(PM_DDR, Buffer1, sizeof(Buffer1));
  DdrConfigData = (DDR_CONFIG *)Buffer1;

  SetMem((VOID*)&ArmSmcArgs, sizeof(ARM_SMC_ARGS), 0);
  Status = GetParameterInfo(PM_PLL, Buffer, sizeof(Buffer));
  if(!EFI_ERROR(Status)) {
#if 0
    if(mOemConfigSueupExist) {
      PllConfigData = (PLL_CONFIG *)Buffer;
      PllConfigData->CoreFrequency = mOemConfigData.CoreFrequency;
      PllConfigData->DdrFrequency = mOemConfigData.DdrFrequency;
    }
#endif
    //override the pbf data with setup data
    PllConfigData = (PLL_CONFIG *)Buffer;
    CoreSpeed = GetCoreSpeed(PeiData);
    if (CoreSpeed != 0) {
      if (CoreSpeed != PllConfigData->CoreFrequency) {
        PllConfigData->CoreFrequency = CoreSpeed;
      }
    }
    LmuSpeed = GetLmuSpeed(PeiData);
    DEBUG((EFI_D_ERROR, "Get Lmu Speed: %d, Core freq: %d\n",LmuSpeed, PllConfigData->CoreFrequency));
    if(LmuSpeed != 0) {
        if(LmuSpeed !=  PllConfigData->DdrFrequency) {
           PllConfigData->DdrFrequency = LmuSpeed;
      }
    }

    if (!(DdrConfigData->ForceSpdEnable)){
      DEBUG((EFI_D_INFO, "DdrConfigData->ForceSpdEnable is 0x%x \n",DdrConfigData->ForceSpdEnable));
      if (PllConfigData->DdrFrequency >= MaxDdrFrequency){
          PllConfigData->DdrFrequency = MaxDdrFrequency;
          // PllConfigData->DdrFrequency = 667;
        }
    }

  } else {
    DEBUG((EFI_D_ERROR, "Get PLL Parameter Fail.\n"));
    while(1);
  }

  DEBUG ((EFI_D_INFO, "[%a:%d] CoreFrequency : %08lx\n", __FUNCTION__, __LINE__, PllConfigData->CoreFrequency));
  DEBUG ((EFI_D_INFO, "[%a:%d] Res1          : %08lx\n", __FUNCTION__, __LINE__, PllConfigData->Res1));
  DEBUG ((EFI_D_INFO, "[%a:%d] DdrFrequency  : %08lx\n", __FUNCTION__, __LINE__, PllConfigData->DdrFrequency));
  DEBUG ((EFI_D_INFO, "[%a:%d] Res2          : %08lx\n", __FUNCTION__, __LINE__, PllConfigData->Res2));
  DEBUG ((EFI_D_INFO, "[%a:%d] Res3          : %08lx\n", __FUNCTION__, __LINE__, PllConfigData->Res3));
  DEBUG ((EFI_D_INFO, "[%a:%d] Res4          : %08lx\n", __FUNCTION__, __LINE__, PllConfigData->Res4));
  DEBUG ((EFI_D_INFO, "[%a:%d] Res5          : %08lx\n", __FUNCTION__, __LINE__, PllConfigData->Res5));

  ArmSmcArgs.Arg0 = CPU_INIT_PLL;
  ArmSmcArgs.Arg1 = 0;
  ArmSmcArgs.Arg2 = (UINTN)PllConfigData;
  ArmCallSmc (&ArmSmcArgs);
}
//[jckuang-0027]
STATIC
EFI_STATUS
GetPcieSetupData(
  IN PARAMETER_PEU_CONFIG  *PeuConfigData,
  IN LocalPeiData          *PeiData
  )
{
  SYSTEM_SETUP_CONFIGURATION* SetupVar = NULL;
  UINT8                       Peu0BaseCfg;
  UINT8                       Peu1BaseCfg;
  UINT8                       PeuCoreLinkSpeed[TOTAL_PEU_NUMBERS][TOTAL_PEU_CORE_NUMBERS]; // = {0,};
  UINT8                       PeuCoreEqualization[TOTAL_PEU_NUMBERS][TOTAL_PEU_CORE_NUMBERS]; // = {0,};
  UINT8                       PeuEnable[TOTAL_PEU_NUMBERS][TOTAL_PEU_CORE_NUMBERS]; //={0,};
  EFI_STATUS                  Status;
  UINT8                       Index;

  Status = EFI_SUCCESS;

  ZeroMem(PeuCoreLinkSpeed, sizeof(PeuCoreLinkSpeed));
  ZeroMem(PeuCoreEqualization, sizeof(PeuCoreEqualization));
  ZeroMem(PeuEnable, sizeof(PeuEnable));

  SetupVar = PeiData->Config;
  DEBUG((EFI_D_INFO,
      "SetupVarAddr:0x%lx,basecfg:0x%x,p1c0speed:0x%x\n,p0c1speed:0x%x,p0c2speed:0x%x\n",
      SetupVar, PeuConfigData->FunctionConfig,
      PeuConfigData->Peu1ControllerConfig[0],
      PeuConfigData->Peu0ControllerConfig[1],
      PeuConfigData->Peu0ControllerConfig[2]));

  if (PeiData->IsVariableValid) {
    Peu0BaseCfg = SetupVar->PcieSettingSplitMode[0] & 0x0f;
    Peu1BaseCfg = SetupVar->PcieSettingSplitMode[1] & 0x0f;
    for (Index = 0; Index < TOTAL_PEU_CORE_NUMBERS; ++Index) {
      PeuEnable[0][Index] = SetupVar->PcieSettingPeu0Enable[Index] & 0x01;
      PeuEnable[1][Index] = SetupVar->PcieSettingPeu1Enable[Index] & 0x01;
      PeuCoreLinkSpeed[0][Index] = SetupVar->PcieSettingPeu0Speed[Index];
      PeuCoreLinkSpeed[1][Index] = SetupVar->PcieSettingPeu1Speed[Index];
      PeuCoreEqualization[0][Index] = SetupVar->PcieSettingPeu0Eq[Index];
      PeuCoreEqualization[1][Index] = SetupVar->PcieSettingPeu1Eq[Index];
      PeuConfigData->Peu0ControllerConfig[Index] = (PeuConfigData->Peu0ControllerConfig[Index] & 0xfffff000) | (PeuEnable[0][Index] << PEU_C_OFFSET_ENABLE) | PeuCoreLinkSpeed[0][Index];
      PeuConfigData->Peu1ControllerConfig[Index] = (PeuConfigData->Peu1ControllerConfig[Index] & 0xfffff000) | (PeuEnable[1][Index] << PEU_C_OFFSET_ENABLE) | PeuCoreLinkSpeed[1][Index];
      PeuConfigData->Peu0ControllerEqualization[Index] = (PeuConfigData->Peu0ControllerEqualization[Index] & 0xfffff000) | PeuCoreEqualization[0][Index];
      PeuConfigData->Peu1ControllerEqualization[Index] = (PeuConfigData->Peu1ControllerEqualization[Index] & 0xfffff000) | PeuCoreEqualization[1][Index];
    }
    PeuConfigData->FunctionConfig &= ~(0x0F | (0x0000F << PEU1_OFFSET));
    PeuConfigData->FunctionConfig |= Peu0BaseCfg | (Peu1BaseCfg << PEU1_OFFSET);
  } else {
    DEBUG((EFI_D_INFO, "Get Pcie Setup data failed! Using Default.\n"));
  }

  return Status;
}
//[jckuang-0027]
VOID PcieInit(
  IN LocalPeiData *PeiData
  )
{
  ARM_SMC_ARGS  ArmSmcArgs;
  EFI_STATUS    Status;
  UINT8 Buffer[0x100];
#if 0
  PEU_CONFIG *PeuConfigData;
  UINT8    Peu0BaseCfg;
  UINT8    Peu1BaseCfg;
  UINT8 Peu0C0LinkSpeed;
  UINT8 Peu0C1LinkSpeed;
  UINT8 Peu0C2LinkSpeed;
  UINT8 Peu1C0LinkSpeed;
  UINT8 Peu1C1LinkSpeed;
  UINT8 Peu1C2LinkSpeed;
#endif
  SetMem((VOID*)&ArmSmcArgs, sizeof(ARM_SMC_ARGS), 0);
  Status = GetParameterInfo(PM_PCIE, Buffer, sizeof(Buffer));
  if(!EFI_ERROR(Status)) {
#if 0
    if(mOemConfigSueupExist) {
      PeuConfigData = (PEU_CONFIG *)Buffer;
      Peu0BaseCfg = mOemConfigData.PcieSplitMode[0];
      Peu1BaseCfg = mOemConfigData.PcieSplitMode[1];
      Peu0C0LinkSpeed = mOemConfigData.PcieLinkSpeedPort[0];
      Peu0C1LinkSpeed = mOemConfigData.PcieLinkSpeedPort[1];
      Peu0C2LinkSpeed = mOemConfigData.PcieLinkSpeedPort[2];
      Peu1C0LinkSpeed = mOemConfigData.PcieLinkSpeedPort[3];
      Peu1C1LinkSpeed = mOemConfigData.PcieLinkSpeedPort[4];
      Peu1C2LinkSpeed = mOemConfigData.PcieLinkSpeedPort[5];
      PeuConfigData->FeaturesConfig[0].BaseConfig[0] = (PeuConfigData->FeaturesConfig[0].BaseConfig[0] & 0xffffff00) & Peu0C0LinkSpeed;
      PeuConfigData->FeaturesConfig[0].BaseConfig[1] = (PeuConfigData->FeaturesConfig[0].BaseConfig[1] & 0xffffff00) & Peu0C1LinkSpeed;
      PeuConfigData->FeaturesConfig[0].BaseConfig[2] = (PeuConfigData->FeaturesConfig[0].BaseConfig[2] & 0xffffff00) & Peu0C2LinkSpeed;
      PeuConfigData->FeaturesConfig[1].BaseConfig[0] = (PeuConfigData->FeaturesConfig[1].BaseConfig[0] & 0xffffff00) & Peu1C0LinkSpeed;
      PeuConfigData->FeaturesConfig[1].BaseConfig[1] = (PeuConfigData->FeaturesConfig[1].BaseConfig[1] & 0xffffff00) & Peu1C1LinkSpeed;
      PeuConfigData->FeaturesConfig[1].BaseConfig[2] = (PeuConfigData->FeaturesConfig[1].BaseConfig[2] & 0xffffff00) & Peu1C2LinkSpeed;
      PeuConfigData->BaseCfg = Peu0BaseCfg | (Peu1BaseCfg << 16);
    }
#endif

      PARAMETER_PEU_CONFIG *Config = (PARAMETER_PEU_CONFIG *)Buffer;

      DEBUG ((EFI_D_INFO, "[%a:%d] IndependentTree    : 0x%08lx\n", __FUNCTION__, __LINE__, Config->IndependentTree));
      DEBUG ((EFI_D_INFO, "[%a:%d] FunctionConfig     : 0x%08lx\n", __FUNCTION__, __LINE__, Config->FunctionConfig));
      ShowHexString("Peu0ControllerConfig", Config->Peu0ControllerConfig, sizeof(Config->Peu0ControllerConfig));
      ShowHexString("Peu0ControllerEqualization", Config->Peu0ControllerEqualization, sizeof(Config->Peu0ControllerEqualization));
      ShowHexString("Peu1ControllerConfig", Config->Peu1ControllerConfig, sizeof(Config->Peu1ControllerConfig));
      ShowHexString("Peu1ControllerEqualization", Config->Peu1ControllerEqualization, sizeof(Config->Peu1ControllerEqualization));

      GetPcieSetupData((PARAMETER_PEU_CONFIG *)Buffer, PeiData);

      DEBUG ((EFI_D_INFO, "[%a:%d] ============    after   =============\n", __FUNCTION__, __LINE__));
      DEBUG ((EFI_D_INFO, "[%a:%d] IndependentTree    : 0x%08lx\n", __FUNCTION__, __LINE__, Config->IndependentTree));
      DEBUG ((EFI_D_INFO, "[%a:%d] FunctionConfig     : 0x%08lx\n", __FUNCTION__, __LINE__, Config->FunctionConfig));
      ShowHexString("Peu0ControllerConfig", Config->Peu0ControllerConfig, sizeof(Config->Peu0ControllerConfig));
      ShowHexString("Peu0ControllerEqualization", Config->Peu0ControllerEqualization, sizeof(Config->Peu0ControllerEqualization));
      ShowHexString("Peu1ControllerConfig", Config->Peu1ControllerConfig, sizeof(Config->Peu1ControllerConfig));
      ShowHexString("Peu1ControllerEqualization", Config->Peu1ControllerEqualization, sizeof(Config->Peu1ControllerEqualization));

  } else {
    DEBUG((EFI_D_ERROR, "Get PCIE Parameter Fail.\n"));
    while(1);
  }

  ArmSmcArgs.Arg0 = CPU_INIT_PCIE;
  ArmSmcArgs.Arg1 = 0;
  ArmSmcArgs.Arg2 = (UINTN)Buffer;
  ArmCallSmc (&ArmSmcArgs);

  if(ArmSmcArgs.Arg0 !=0) {
    DEBUG((EFI_D_INFO, "PCIe Init fail.\n"));
    ASSERT(FALSE);
  }
}

VOID
DdrInit(
  IN UINT32       S3Flag,
  IN LocalPeiData *PeiData
  )
{
  UINT8         Buffer[0x100];
  UINT32        Index;
  ARM_SMC_ARGS  ArmSmcArgs;
  DDR_CONFIG    *DdrConfigData;
  EFI_STATUS    Status;
  //DDR_CONFIG_DATA    DdrConfig;
  SYSTEM_SETUP_CONFIGURATION                          *SetupVar = NULL;
  UINT8  FastTrainEnable = 0;

  //UINTN         VarSize;
  UINT64        DdrInfoAddr;

  SetupVar = PeiData->Config;
  DdrInfoAddr =  PcdGet64 (PcdDdrTrainInfoSaveBaseAddress);
  DEBUG ((EFI_D_INFO, "Pcd DdrInfoAddr : %x\n", DdrInfoAddr));
  //
  //Get cpu config, include fast training switch.
  //
  //[gliu-0009]
  //VarSize = sizeof (DDR_CONFIG_DATA);
  //ZeroMem (&DdrConfig, sizeof (DDR_CONFIG_DATA));
  //[gliu-0009]
  DEBUG ((EFI_D_INFO, "Pcd DdrInfoAddr : %x, line : %d\n", DdrInfoAddr, __LINE__));
  //[gliu-0009]add-start
  /*Status = SearchAnyVariable (
             VAR_CPU_DDR_CONFIG_NAME,
             &gCpuDdrConfigVarGuid,
             &DdrConfig,
             &VarSize);*/
  //[gliu-0009]add-end
  if (PeiData->IsVariableValid) {
    DEBUG ((EFI_D_INFO, "Get Cpu Ddr Config Variable Success\n"));
    FastTrainEnable = SetupVar->FastTrainEnable;
  }
  else {
    FastTrainEnable = 0;
    DEBUG ((EFI_D_INFO, "Get Cpu Ddr Config Variable Failed\n"));
  }
  DEBUG ((EFI_D_INFO, "DdrConfig.FastTrainEnable : %d\n", FastTrainEnable));
  if (FastTrainEnable != 0) {
    if (!CheckTrainInfo (DdrInfoAddr)) {
      DEBUG ((EFI_D_INFO, "Check Train Info Failed!Disabled Fast Train.\n"));
      FastTrainEnable = 0;
    }
  }

  DEBUG ((EFI_D_INFO, "Pcd DdrInfoAddr : %x, line : %d\n", DdrInfoAddr, __LINE__));
  Status = GetParameterInfo(PM_DDR, Buffer, sizeof(Buffer));
  if(!EFI_ERROR(Status)) {
    DEBUG((EFI_D_INFO, "%a() Line=%d\n", __FUNCTION__, __LINE__));
    DdrConfigData = (DDR_CONFIG *)Buffer;
    if(mOemConfigSueupExist) {
      DdrConfigData->ChannelEnable = mOemConfigData.ChannelEnable;
      DdrConfigData->EccEnable = mOemConfigData.EccEnable;
      DdrConfigData->DmEnable = mOemConfigData.DmEnable;
    } else {
      DEBUG((EFI_D_INFO, "%a() Line=%d\n", __FUNCTION__, __LINE__));
      GetDdrConfigParameter(DdrConfigData, S3Flag);
    }
  } else {
    DEBUG((EFI_D_ERROR, "Get DDR Parameter Fail.\n"));
    while(1);
  }

  //
  //S3 resume ddr init
  //
  if (S3Flag) {
    //[jckuang-0020]
    POST_CODE_EX (EFI_PROGRESS_CODE, S3_RESTORE_MEMORY_CONTROLLER);
    //[jckuang-0020]
    SetMem((VOID*)&ArmSmcArgs, sizeof(ARM_SMC_ARGS), 0);
    ArmSmcArgs.Arg0 = CPU_INIT_DDR;
    ArmSmcArgs.Arg1 = DDR_INIT;
    ArmSmcArgs.Arg2 = (UINTN)Buffer;
    ArmCallSmc (&ArmSmcArgs);

    if (0 != ArmSmcArgs.Arg0) {
      DEBUG ((EFI_D_ERROR, "Error X0:0x%x, X1:0x%x\n", ArmSmcArgs.Arg0, ArmSmcArgs.Arg1));
      for (Index = 0; Index < 8; Index++) {
        if (((ArmSmcArgs.Arg1 >> 24) & 0xff) & (1 << Index)) {
          DEBUG((EFI_D_ERROR, "Channel %d ", Index));
          break;
        }
      }
      switch (ArmSmcArgs.Arg1 & 0xffffff) {
        case 0x1:
          DEBUG((EFI_D_ERROR, "Traning Fail!\n"));
          Alarm(ERROR_TYPE1);
          break;
        default:
          DEBUG((EFI_D_ERROR, "Error Code: 0x%x\n", ArmSmcArgs.Arg1 & 0xffffff));
          break;
      }
      while (1);
    }
  }
  //
  //normal ddr init
  //
  else {
    //[jckuang-0020]
    POST_CODE_EX (EFI_PROGRESS_CODE, PEI_MEMORY_INIT);
    //[jckuang-0020]
    //
    //fast training
    //
    if (1 == FastTrainEnable) {
      ZeroMem (&ArmSmcArgs, sizeof(ARM_SMC_ARGS));
      ArmSmcArgs.Arg0 = CPU_INIT_DDR;
      ArmSmcArgs.Arg1 = DDR_FAST_TRAINNING;
      ArmSmcArgs.Arg2 = (UINTN)Buffer;
      ArmSmcArgs.Arg3 = (UINTN)DdrInfoAddr + 4;
      ArmCallSmc (&ArmSmcArgs);

      if (0 != ArmSmcArgs.Arg0) {
        POST_CODE_EX (EFI_ERROR_CODE, PEI_MEMORY_ERROR);//[gliu-0062]
        DEBUG ((EFI_D_ERROR, "Error X0:0x%x, X1:0x%x\n", ArmSmcArgs.Arg0, ArmSmcArgs.Arg1));
        for (Index = 0; Index < 8; Index++) {
          if (((ArmSmcArgs.Arg1 >> 24) & 0xff) & (1 << Index)) {
            DEBUG((EFI_D_ERROR, "Channel %d ", Index));
            break;
          }
        }
        switch (ArmSmcArgs.Arg1 & 0xffffff) {
          case 0x1:
            DEBUG((EFI_D_ERROR, "Traning Fail!\n"));
            Alarm(ERROR_TYPE1);
            break;
          default:
            DEBUG((EFI_D_ERROR, "Error Code: 0x%x\n", ArmSmcArgs.Arg1 & 0xffffff));
            break;
        }
        while (1);
      }
      //
      //BIST
      //
      ZeroMem (&ArmSmcArgs, sizeof(ARM_SMC_ARGS));
      ArmSmcArgs.Arg0 = CPU_INIT_DDR;
      ArmSmcArgs.Arg1 = DDR_BIST;
      ArmSmcArgs.Arg2 = DdrConfigData->ChannelEnable;
      ArmCallSmc (&ArmSmcArgs);
      if (0 == ArmSmcArgs.Arg0) {
        DEBUG ((EFI_D_INFO, "Bist OK\n"));
        CreatDdrTrainInfoHob ();
#if 0
        //
        //Get Ddr Training Info from pbf
        //
        ZeroMem (&ArmSmcArgs, sizeof(ARM_SMC_ARGS));
        ArmSmcArgs.Arg0 = CPU_GET_MEM_INFO;
        ArmCallSmc (&ArmSmcArgs);
        if (0 == ArmSmcArgs.Arg0) {
          DEBUG ((EFI_D_INFO, "Get ddr training info from pbf failed!\n"));
        }
        else {
          DdrInfoSrc = ArmSmcArgs.Arg0;
          DdrInfoSize = MmioRead64 (ArmSmcArgs.Arg0);
          DdrInfoAddr =  PcdGet64 (PcdDdrTrainInfoSaveBaseAddress);
          DEBUG ((EFI_D_INFO, "Ddr Info Size : %d, Addr : %x\n", DdrInfoSize, DdrInfoSrc));
          DEBUG ((EFI_D_INFO, "DdrInfoAddr : %x\n", DdrInfoAddr));
          SetDdrTrainInfoToFlash (DdrInfoSrc, DdrInfoAddr, DdrInfoSize);
        }
#endif
      }
      else {
        //
        //retraining
        //
        ZeroMem (&ArmSmcArgs, sizeof(ARM_SMC_ARGS));
        ArmSmcArgs.Arg0 = CPU_INIT_DDR;
        ArmSmcArgs.Arg1 = DDR_INIT;
        ArmSmcArgs.Arg2 = (UINTN)Buffer;
        ArmCallSmc (&ArmSmcArgs);

        DEBUG ((EFI_D_INFO, "Pcd DdrInfoAddr : %x, line : %d\n", DdrInfoAddr, __LINE__));
        if (0 != ArmSmcArgs.Arg0) {
          DEBUG ((EFI_D_ERROR, "Error X0:0x%x, X1:0x%x\n", ArmSmcArgs.Arg0, ArmSmcArgs.Arg1));
          for (Index = 0; Index < 8; Index++) {
            if (((ArmSmcArgs.Arg1 >> 24) & 0xff) & (1 << Index)) {
              DEBUG((EFI_D_ERROR, "Chanle %d ", Index));
              break;
            }
          }
          switch (ArmSmcArgs.Arg1 & 0xffffff) {
            case 0x1:
              DEBUG((EFI_D_ERROR, "Traning Fail!\n"));
              Alarm(ERROR_TYPE1);
              break;
            default:
              DEBUG((EFI_D_ERROR, "Error Code: 0x%x\n", ArmSmcArgs.Arg1 & 0xffffff));
              break;
          }
          while (1);
        }
        CreatDdrTrainInfoHob ();
#if 0
        //
        //Get Ddr Training Info from pbf
        //
        DEBUG ((EFI_D_INFO, "Pcd DdrInfoAddr : %x, line : %d\n", DdrInfoAddr, __LINE__));
        ZeroMem (&ArmSmcArgs, sizeof(ARM_SMC_ARGS));
        ArmSmcArgs.Arg0 = CPU_GET_MEM_INFO;
        ArmCallSmc (&ArmSmcArgs);
        if (0 == ArmSmcArgs.Arg0) {
          DEBUG ((EFI_D_INFO, "Get ddr training info from pbf failed!\n"));
        }
        else {
          DEBUG ((EFI_D_INFO, "Pcd DdrInfoAddr : %x, line : %d\n", DdrInfoAddr, __LINE__));
          DdrInfoSrc = ArmSmcArgs.Arg0;
          DdrInfoSize = MmioRead64 (ArmSmcArgs.Arg0);
          DdrInfoAddr =  PcdGet64 (PcdDdrTrainInfoSaveBaseAddress);
          DEBUG ((EFI_D_INFO, "Ddr Info Size : %d, Addr : %x\n", DdrInfoSize, DdrInfoSrc));
          DEBUG ((EFI_D_INFO, "DdrInfoAddr : %x\n", DdrInfoAddr));
          SetDdrTrainInfoToFlash (DdrInfoSrc, DdrInfoAddr, DdrInfoSize);
        }
#endif
      }
    }
    //
    //not fast traing
    //
    else {
      DEBUG ((EFI_D_INFO, "Pcd DdrInfoAddr : %x, line : %d\n", DdrInfoAddr, __LINE__));
      ZeroMem (&ArmSmcArgs, sizeof(ARM_SMC_ARGS));
      ArmSmcArgs.Arg0 = CPU_INIT_DDR;
      ArmSmcArgs.Arg1 = DDR_INIT;
      ArmSmcArgs.Arg2 = (UINTN)Buffer;
      ArmCallSmc (&ArmSmcArgs);

      DEBUG ((EFI_D_INFO, "Pcd DdrInfoAddr : %x, line : %d\n", DdrInfoAddr, __LINE__));
      if (0 != ArmSmcArgs.Arg0) {
        DEBUG ((EFI_D_ERROR, "Error X0:0x%x, X1:0x%x\n", ArmSmcArgs.Arg0, ArmSmcArgs.Arg1));
        for (Index = 0; Index < 8; Index++) {
          if (((ArmSmcArgs.Arg1 >> 24) & 0xff) & (1 << Index)) {
            DEBUG((EFI_D_ERROR, "Chanle %d ", Index));
            break;
          }
        }
        switch (ArmSmcArgs.Arg1 & 0xffffff) {
          case 0x1:
            DEBUG((EFI_D_ERROR, "Traning Fail!\n"));
            Alarm(ERROR_TYPE1);
            break;
          default:
            DEBUG((EFI_D_ERROR, "Error Code: 0x%x\n", ArmSmcArgs.Arg1 & 0xffffff));
            break;
        }
        while (1);
      }
      CreatDdrTrainInfoHob ();
#if 0
      //
      //Get Ddr Training Info from pbf
      //
      DEBUG ((EFI_D_INFO, "Pcd DdrInfoAddr : %x, line : %d\n", DdrInfoAddr, __LINE__));
      ZeroMem (&ArmSmcArgs, sizeof(ARM_SMC_ARGS));
      ArmSmcArgs.Arg0 = CPU_GET_MEM_INFO;
      ArmCallSmc (&ArmSmcArgs);
      if (0 == ArmSmcArgs.Arg0) {
        DEBUG ((EFI_D_INFO, "Get ddr training info from pbf failed!\n"));
      }
      else {
        DEBUG ((EFI_D_INFO, "Pcd DdrInfoAddr : %x, line : %d\n", DdrInfoAddr, __LINE__));
        DdrInfoSrc = ArmSmcArgs.Arg0;
        DdrInfoSize = MmioRead64 (ArmSmcArgs.Arg0);
        DdrInfoAddr =  PcdGet64 (PcdDdrTrainInfoSaveBaseAddress);
        DEBUG ((EFI_D_INFO, "Ddr Info Size : %d, Addr : %x\n", DdrInfoSize, DdrInfoSrc));
        DEBUG ((EFI_D_INFO, "DdrInfoAddr : %x\n", DdrInfoAddr));
        SetDdrTrainInfoToFlash (DdrInfoSrc, DdrInfoAddr, DdrInfoSize);
      }
#endif
    }
  }
#if 0
  ArmSmcArgs.Arg0 = CPU_INIT_DDR;
  ArmSmcArgs.Arg1 = DDR_INIT;
  ArmSmcArgs.Arg2 = (UINTN)Buffer;
  ArmCallSmc (&ArmSmcArgs);

  if (0 != ArmSmcArgs.Arg0) {
    DEBUG ((EFI_D_ERROR, "Error X0:0x%x, X1:0x%x\n", ArmSmcArgs.Arg0, ArmSmcArgs.Arg1));
    for (Index = 0; Index < 8; Index++) {
      if (((ArmSmcArgs.Arg1 >> 24) & 0xff) & (1 << Index)) {
        DEBUG((EFI_D_ERROR, "Chanle %d ", Index));
        break;
      }
    }
    switch (ArmSmcArgs.Arg1 & 0xffffff) {
      case 0x1:
        DEBUG((EFI_D_ERROR, "Traning Fail!\n"));
        Alarm(ERROR_TYPE1);
        break;
      default:
        DEBUG((EFI_D_ERROR, "Error Code: 0x%x\n", ArmSmcArgs.Arg1 & 0xffffff));
        break;
    }
    while (1);
  }
#endif

  if(S3Flag) {
    mdelay(10);
    enable_vtt();
    mdelay(40);
    SetMem((VOID*)&ArmSmcArgs, sizeof(ARM_SMC_ARGS), 0);
    ArmSmcArgs.Arg0 = CPU_INIT_DDR;
    ArmSmcArgs.Arg1 = DDR_SUSPEND_UNLOCK;
    ArmCallSmc (&ArmSmcArgs);
  }
}
STATIC
EFI_STATUS GetCoreBitMap(
  IN UINTN        *CoreBitMap,
  IN LocalPeiData *PeiData
  )
{
  UINT32                      CoreIndex;
  UINTN                       Map;
  SYSTEM_SETUP_CONFIGURATION  *SetupVar;
  EFI_STATUS                  Status;

  CoreIndex = 0;
  Map = 0;
  SetupVar = PeiData->Config;
  Status = EFI_SUCCESS;

  if (NULL == CoreBitMap) {
      return EFI_INVALID_PARAMETER;
  }

  if (!PeiData->IsVariableValid) {
    DEBUG ((EFI_D_INFO, "Get CoreBitMap failed! Using Default.\n"));
  } else {
    //Note: Currently, only 64 cores are supported
    for (CoreIndex = 0; CoreIndex < sizeof(SetupVar->CoreSettingEnable)/sizeof(SetupVar->CoreSettingEnable[0]); ++CoreIndex) {
      if (1 == SetupVar->CoreSettingEnable[CoreIndex]) {
        if (0 == (CoreIndex & 0x1)) {
          Map |= (1<<(CoreIndex<<1));
        } else {
          Map |= (1 << ((CoreIndex<<1)-1));
        }
      }
    }

    DEBUG ((EFI_D_INFO, "Get CoreBitMap : 0x%lx \n", Map));
    *CoreBitMap = Map;
  }

  return Status;
}


#define PEU0_PHY_BASE 0x29200000
#define PEU1_PHY_BASE 0x29300000

#define TX_A0_LANX_BASE  0x10400
#define TX_A0_LANY_BASE  0x10C00
#define TX_A1_LANX_BASE  0x10404
#define TX_A1_LANY_BASE  0x10C04
#define TX_A2_LANX_BASE  0x10408
#define TX_A2_LANY_BASE  0x10C08
#define TX_A3_LANX_BASE  0x1040C
#define TX_A3_LANY_BASE  0x10C0C
#define TX_A4_LANX_BASE  0x10410
#define TX_A4_LANY_BASE  0x10C10
#define TX_A5_LANX_BASE  0x10414
#define TX_A5_LANY_BASE  0x10C14


#define RX_A0_LANX_BASE  0x20000
#define RX_A0_LANY_BASE  0x20800
#define RX_A1_LANX_BASE  0x20004
#define RX_A1_LANY_BASE  0x20804
#define RX_A2_LANX_BASE  0x20008
#define RX_A2_LANY_BASE  0x20808
#define RX_A3_LANX_BASE  0x2000C
#define RX_A3_LANY_BASE  0x2080C
#define RX_A4_LANX_BASE  0x20010
#define RX_A4_LANY_BASE  0x20810
#define RX_A5_LANX_BASE  0x20014
#define RX_A5_LANY_BASE  0x20814

#define LAN_STEP      0x1000


VOID
TzcAesInit (
  VOID
  )
{
  //tzc aes init
  UINT8                Buff[0x100];
  ARM_SMC_ARGS         ArmSmcArgs;
  UINT64               SecureAddr;

  DEBUG((EFI_D_INFO,"Tzc aes init begin\n"));
  SetMem((VOID*)&ArmSmcArgs, sizeof(ARM_SMC_ARGS), 0);
  ArmSmcArgs.Arg0 = CPU_INIT_DDR;
  ArmSmcArgs.Arg1 = TAZ_AES_INIT;
  ArmSmcArgs.Arg2 = (UINTN)Buff;
  SecureAddr = O_PARAMETER_BASE + PM_SECURE_OFFSET;

  CopyMem(Buff, (VOID *)SecureAddr, sizeof(SECURE_BASE_INFO));
  ArmCallSmc (&ArmSmcArgs);
  if (0 != ArmSmcArgs.Arg0){
    DEBUG((EFI_D_ERROR,"read TZC AES config error in Parameter\n"));
  }
}

/*
* S3Flag = 0, power on
* S3Flag = 1, Recover from S3
*/
VOID
CpuRelocate(
  IN UINT8 S3Flag,
  IN LocalPeiData *PeiData
  )
{
  ARM_SMC_ARGS  ArmSmcArgs;
  UINT8         Buffer[0x100];
  COMMON_CONFIG *CommonConfig;
  UINTN         CoreBitMap;
  EFI_STATUS    Status;

  SetMem((VOID*)&ArmSmcArgs, sizeof(ARM_SMC_ARGS), 0);
  CoreBitMap = 0;
  Status = GetParameterInfo(PM_COMMON, Buffer, sizeof(Buffer));
  if(!EFI_ERROR(Status)) {
#if 0
    if(mOemConfigSueupExist) {
      CommonConfig = (COMMON_CONFIG *)Buffer;
      CommonConfig->CoreBitMap = mOemConfigData.CoreBitMap;
    }
#endif
    if(EFI_SUCCESS == GetCoreBitMap(&CoreBitMap, PeiData)) {
      CommonConfig = (COMMON_CONFIG *)Buffer;
      CommonConfig->CoreBitMap = CoreBitMap;
    }

  } else {
    DEBUG((EFI_D_ERROR, "Get Common Parameter Fail.\n"));
    while (1);
  }

  ArmSmcArgs.Arg0 = CPU_RELOCATE;
  ArmSmcArgs.Arg1 = S3Flag;
  ArmSmcArgs.Arg2 = (UINTN)Buffer;
  ArmCallSmc (&ArmSmcArgs);

  if (ArmSmcArgs.Arg0 !=0) {
    DEBUG((EFI_D_INFO, "Cpu Relocate fail.\n"));
    ASSERT(FALSE);
  }
}


VOID
PcieLowPowerConfig (
  IN UINT32 PeuBase
  )
{
  UINT8 Index;

  for (Index = 0; Index < 8; Index++) {
    //A0
    MmioWrite32(PeuBase + TX_A0_LANX_BASE + Index * LAN_STEP, 0);
    MmioWrite32(PeuBase + TX_A0_LANY_BASE + Index * LAN_STEP, 0);
    //A1
    MmioWrite32(PeuBase + TX_A1_LANX_BASE + Index * LAN_STEP, 0);
    MmioWrite32(PeuBase + TX_A1_LANY_BASE + Index * LAN_STEP, 0);
    //A2
    MmioWrite32(PeuBase + TX_A2_LANX_BASE + Index * LAN_STEP, 0);
    MmioWrite32(PeuBase + TX_A2_LANY_BASE + Index * LAN_STEP, 0);
    //A3
    MmioWrite32(PeuBase + TX_A3_LANX_BASE + Index * LAN_STEP, 0);
    MmioWrite32(PeuBase + TX_A3_LANY_BASE + Index * LAN_STEP, 0);
    //A4
    MmioWrite32(PeuBase + TX_A4_LANX_BASE + Index * LAN_STEP, 0);
    MmioWrite32(PeuBase + TX_A4_LANY_BASE + Index * LAN_STEP, 0);
    //A5
    MmioWrite32(PeuBase + TX_A5_LANX_BASE + Index * LAN_STEP, 0);
    MmioWrite32(PeuBase + TX_A5_LANY_BASE + Index * LAN_STEP, 0);

    //A0
    MmioWrite32(PeuBase + RX_A0_LANX_BASE + Index * LAN_STEP, 0);
    MmioWrite32(PeuBase + RX_A0_LANY_BASE + Index * LAN_STEP, 0);
    //A1
    MmioWrite32(PeuBase + RX_A1_LANX_BASE + Index * LAN_STEP, 0);
    MmioWrite32(PeuBase + RX_A1_LANY_BASE + Index * LAN_STEP, 0);
    //A2
    MmioWrite32(PeuBase + RX_A2_LANX_BASE + Index * LAN_STEP, 0);
    MmioWrite32(PeuBase + RX_A2_LANY_BASE + Index * LAN_STEP, 0);
    //A3
    MmioWrite32(PeuBase + RX_A3_LANX_BASE + Index * LAN_STEP, 0);
    MmioWrite32(PeuBase + RX_A3_LANY_BASE + Index * LAN_STEP, 0);
    //A4
    MmioWrite32(PeuBase + RX_A4_LANX_BASE + Index * LAN_STEP, 0);
    MmioWrite32(PeuBase + RX_A4_LANY_BASE + Index * LAN_STEP, 0);
    //A5
    MmioWrite32(PeuBase + RX_A5_LANX_BASE + Index * LAN_STEP, 0);
    MmioWrite32(PeuBase + RX_A5_LANY_BASE + Index * LAN_STEP, 0);
  }
}
/*++

Routine Description:



Arguments:

  FileHandle  - Handle of the file being invoked.
  PeiServices - Describes the list of possible PEI Services.

Returns:

  Status -  EFI_SUCCESS if the boot mode could be set

--*/
EFI_STATUS
EFIAPI
InitializePlatformPeim (
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
  IN CONST EFI_PEI_SERVICES     **PeiServices
  )
{
  EFI_STATUS                    Status;
  EFI_BOOT_MODE                 BootMode;
  UINT32                        ResetSource;
  UINT32                        S3Flag;
  UINT16                        MaxDdrFrequency;
//AUTO_WAKE_UP_CONFIG_DATA      AutoWakeUpConfigData;
//  UINTN                         VarSize;
//  UINT32                        QspiFreq;
//[gliu-0004]
  UINT16                        BootTimeOut = 0;
//[gliu-0004]
  SYSTEM_SETUP_CONFIGURATION    *SetupVar;
  LocalPeiData                  *LocalPeiDataPtr = NULL;

////////
  MaxDdrFrequency =0;
//  PeiSerialPortInitialize();//[gliu-0046]
  //VarSize = sizeof(AUTO_WAKE_UP_CONFIG_DATA);
  //ZeroMem(&AutoWakeUpConfigData, VarSize);
  DEBUG ((EFI_D_LOAD | EFI_D_INFO, "Platform PEIM Loaded\n"));
  Status = PeiServicesSetBootMode (ArmPlatformGetBootMode ());
  ASSERT_EFI_ERROR (Status);

  PlatformPeim ();

  Status = PeiServicesGetBootMode (&BootMode);
  ASSERT_EFI_ERROR (Status);

  Status = PeiServicesInstallPpi (&mPpiListBootMode);
  ASSERT_EFI_ERROR (Status);

  if (BootMode == BOOT_IN_RECOVERY_MODE) {
    Status = PeiServicesInstallPpi (&mPpiListRecoveryBootMode);
    ASSERT_EFI_ERROR (Status);
  }

#if ((defined NOTEBOOK_V1) || (defined NOTEBOOK_V2))
  PcieLowPowerConfig(PEU0_PHY_BASE);
  PcieLowPowerConfig(PEU1_PHY_BASE);
#endif

  LocalPeiDataPtr = AllocateZeroPool(sizeof(LocalPeiData));
  if (!LocalPeiDataPtr) {
    DEBUG ((DEBUG_ERROR, "[+][%a:%d] allocate pool failed.\n", __FUNCTION__, __LINE__));
  }
  Status = VariableGet(LocalPeiDataPtr);
  DEBUG ((DEBUG_ERROR, "[+][%a:%d] VariableSafeScanAndGet: %r\n", __FUNCTION__, __LINE__, Status));

  //
  //  read spd to get MaxFreq
  //
  ResetSource = GetResetSource();
  if (POWER_ON_RESET == ResetSource) {
    //Enhance qspi speed to read spd
    //QspiFreq = MmioRead32(0x28014004);
    //QspiFreq = (QspiFreq & (1 << 2)) | 0x6;
    //MmioWrite32(0x28014004, QspiFreq);

    MaxDdrFrequency = GetMaxFreq();
    PllInit(MaxDdrFrequency, LocalPeiDataPtr);
  } else {
    SetupVar = LocalPeiDataPtr->Config;
    InitializeGpio();//[gliu-0043]
    S3Flag = get_s3_flag();
//[gliu-0004]
    if(S3Flag != 1){
      if (LocalPeiDataPtr->IsVariableValid) {
        StartWatchdog(SetupVar->watchdog.Enable, SetupVar->watchdog.WatchdogTimeOut, &BootTimeOut);
      }
    } else {
      StopWatchdog();
    }
//[gliu-0004]
     /*Status = SearchAnyVariable (
             VAR_CPU_AUTO_WAKE_UP_CONFIG_NAME,
             &gCpuAutoWakeUpVarGuid,
             &AutoWakeUpConfigData,
             &VarSize);*/


    DEBUG((EFI_D_INFO,"AutoS3 is %d\n",SetupVar->AutoWakeUpConfig.AutoS3));
    DEBUG((EFI_D_INFO,"AutoS4S5 is %d\n",SetupVar->AutoWakeUpConfig.AutoS4S5));
    DEBUG((EFI_D_INFO,"S3WakeUpTime is %d\n",SetupVar->AutoWakeUpConfig.S3WakeUpTime));
    DEBUG((EFI_D_INFO,"S4S5WakeUpTime is %d\n",SetupVar->AutoWakeUpConfig.S4S5WakeUpTime));
    AutoWakeUp(&SetupVar->AutoWakeUpConfig);
    clean_s3_flag();
    ClearRTCInterrupt();
    PcieInit(LocalPeiDataPtr);
    DdrInit(S3Flag, LocalPeiDataPtr);
    TzcAesInit();
//[gliu-0034]add-start
#if S3_RESUME_UNLOCK_HDD
  if(S3Flag != 1){
#endif
      CpuRelocate(S3Flag, LocalPeiDataPtr);
#if S3_RESUME_UNLOCK_HDD
    } else {
      DEBUG ((DEBUG_INFO, "enter S3Flag=1 \n"));
      POST_CODE_EX(EFI_PROGRESS_CODE, PEI_S3_STARTED);
      Status = PeiServicesInstallPpi (&mPpiListX100Info);
      Status = PeiServicesSetBootMode (BOOT_ON_S3_RESUME);
      ASSERT_EFI_ERROR (Status);
    }
#endif
//[gliu-0034]add-end
  }

  return Status;
}
